#ifndef VERTEXSET_H
#define VERTEXSET_H

// the class that contains a set of vertices: this is used for the improved greedy search and interchangable vertices
#include "VertexBase.h"
#include "Vertex.h"
#include "VertexDirectory.h"
#include <iostream>
#include <set>
#include <string>

using namespace std;

typedef vector<bool> VertexKey;
typedef pair<VertexKey, VertexKey> VertexSetKey;
class VertexDirectory;

class VertexSet : public VertexBase
{
public:
	VertexSet(VertexDirectory *dir = NULL);
	~VertexSet();
	VertexSet(pair<Vertex*, Vertex*> vertices);
	VertexSet(Vertex *vertex1, Vertex *vertex2);
	int Size();
	bool IsInGraph();
	Vertex *Vertex1();
	Vertex *Vertex2();
	bool operator==(VertexSet &otherVertexSet);
	bool operator!=(VertexSet &otherVertexSet);
	VertexSetKey Name();
	string PrintName();

	// copies vertexToCopy's data INTO this instance
	void VertexSet::Copy(Vertex* vertex1ToCopy, Vertex *vertex2ToCopy);

	bool Neighbours(VertexBase* otherVertex);
	bool NeighboursInGraph(VertexBase* otherVertex);
	bool NeighboursNotInGraph(VertexBase* otherVertex);
	
	bool Interchangeable();
	bool IsReplacement();
	set<VertexSetKey> GetReplacements();
	set<VertexSetKey> GetInterchangeables();
	void SetInterchangeableFlag(bool value);
	void SetReplacementFlag(bool value);
	
	
	// Set flags, adds other vertex to replacement list
	void SetInterchangeable(VertexBase* otherVertexSet, bool updateContainer);
	// removes other vertex from replacement list
	void ResetInterchangeableWithVertexSet(VertexSet* otherVertexSet);
	// Marks this vertex is not interchangeable - clears flags and m_replacements, removes it from all m_Vertices to replace
	void ResetInterchangeable();
	// Adds vertex to m_VerticesToReplace list
	void  SetAsReplacementFor(VertexBase* otherVertexSet);
	// Removes vertex from m_VerticesToReplace list
	void ResetReplacementForVertexSet(VertexSet* otherVertexSet);
	// Clears flags, clears m_VerticesToReplace, removes from all m_replacements lists
	void ResetIsReplacement();
	bool CanBeReplaced();
	bool CanReturnToOriginalGroup();
	bool CanBeRemovedFromReplacements();
	void UpdateReplacementState();
	void UpdateReplacementStateForAllNeighboursInGraph();
	bool CanAllRelatedInterchangeablesBeReplaced();
	bool HasNeighbourInGroup(Group *group);
	bool ChosenToReplace(VertexSet *replacedVertex);
	void Replace(Graph *graph);
	void ReturnToOriginalContainer(bool updateFlags = true);
	void RemoveAllReplacements();
	void UndoReplacement(Graph *graph);
	Group *GetVerticesOriginalGroup();
	Graph *GetContainingGraph();
	VertexContainer* GetPreviousContainer();
	VertexContainer* GetCurrentContainer();
	void ClearInterchangeableInformation();
	void FindReplacements(Graph *graph); 
	void ClearContainingSets();

private:

	Vertex *m_Vertex1;
	Vertex *m_Vertex2;

	// if m_Interchangeable == true, this is a list of the vertices this vertex can be replaced with
	set<VertexSetKey> m_Replacements;
	// if m_Replacement == true, this is a list of the vertices this vertex can replace
	set<VertexSetKey> m_VerticesToReplace;

	VertexDirectory *m_VertexDirectory;

	void ReplaceWith(VertexSet *replacementVertex,Graph *graph, bool updateFlags);
	VertexSet *GetLegalReplacementVertexSet();
	set<VertexSet*> GetAllRelatedInterchangeables();
	set<VertexSet*> GetAllRelatedReplacements();
	void AddInterchangeableVertexSetFromVertexNeighbours(Vertex *vertex, set<VertexSet*> *resultSet);
	void AddReplacementVertexSetFromVertexNeighbours(Vertex *vertex, set<VertexSet*> *resultSet);
	bool CanWholeListBeReplaced(set<VertexSet*> interchangeables);	
	void UndoReplacementWith(VertexSet *otherVertex, bool returnToGraph);
	bool CanInterchangeableVertexSetBeReplaced();
	bool CanReplacementVertexSetBeRemovedFromReplacements();
	void ReplaceInterchangeableSet(Graph *graph);
	void ResetReplacementSet();
	bool CanReturnToGroupForInterchangeable();
};

#endif